package pro.view.adaptor;

import java.awt.Point;
import java.util.*;
import javax.swing.ImageIcon;
import pro.model.core.*;
import pro.resources.ResourceLocator;
import pro.view.core.*;


/**
 * @author  sangwo.y
 */
public class Wrapper extends Observable {

	private String ANONYMOUS_PLAYER = "test"; //System.getProperty("user.name");  //
	private Game game;
	private GameView gv;
	
	private List<IHolder> holders;
	
	/**
	 * @uml.property  name="piles"
	 * @uml.associationEnd  multiplicity="(0 -1)"
	 */
	private Pile[] piles;
	/**
	 * @uml.property  name="columns"
	 * @uml.associationEnd  multiplicity="(0 -1)"
	 */
	private Column[] columns;
	
	private List<IHolder> endCells;
		
	private IHolder srcHolder = null;
	private String player = ANONYMOUS_PLAYER;
	
	private long startTime;
		
	
	public Wrapper(Game game, GameView gv) {
		this.gv=gv;
		this.game=game;
		fillHolders();	
	}
	
	public boolean hasWon() {
		return (game.getScore()==0);
	}
	
	public void startTimer() {
		startTime = System.currentTimeMillis();
		//System.out.println("start: "+startTime);
	}
	
	public long stopTimer() {
		return System.currentTimeMillis() - startTime;
	}
	
	/**
	 * @return  the player
	 * @uml.property  name="player"
	 */
	public String getPlayer() {
		return player;
	}
	
	
	public int getDuration() {
		
		return (int)(stopTimer()/1000);
		/*
		*/
	}
	
	public static String getStringDuration(int intDuration) {
		int hours, minutes;
		int time =intDuration;
		hours = (int) time / 3600;
		String h ="";
		String m = "";
		String s = "";
		if (hours<10) h="0";
		time = time - (hours * 3600);		
		minutes = (int) time / 60;
		if (minutes<10) m="0";
		time = time - (minutes * 60);
		if (time<10) s="0";
		return new String(h+hours+":"+m+minutes+":"+s+time);
	}
	
	public int getScore() {
		return game.getScore();
	}
	
	private void fillHolders() {
		holders = new ArrayList<IHolder>();
		fillColumns();
		fillFreeCells();
		fillEndCells();
	}
	
	/**
	 * @param player  the player to set
	 * @uml.property  name="player"
	 */
	public void setPlayer(String player) {
		this.player=player;
	}
	
	private void fillEndCells() {
		Cell ec1 = new Cell(21, gv, new Point(GameView.END_CELL_X_STEP+GameView.CELL_X_OFFSET
				+0*(GameView.CARD_WIDTH+GameView.CELL_X_OFFSET),GameView.CELL_Y_OFFSET));
		Cell ec2 = new Cell(22, gv, new Point(GameView.END_CELL_X_STEP+GameView.CELL_X_OFFSET
				+1*(GameView.CARD_WIDTH+GameView.CELL_X_OFFSET),GameView.CELL_Y_OFFSET));
		Cell ec3 = new Cell(23, gv, new Point(GameView.END_CELL_X_STEP+GameView.CELL_X_OFFSET
				+2*(GameView.CARD_WIDTH+GameView.CELL_X_OFFSET),GameView.CELL_Y_OFFSET));
		Cell ec4 = new Cell(24, gv, new Point(GameView.END_CELL_X_STEP+GameView.CELL_X_OFFSET
				+3*(GameView.CARD_WIDTH+GameView.CELL_X_OFFSET),GameView.CELL_Y_OFFSET));
		
		holders.add(ec1);
		holders.add(ec2);
		holders.add(ec3);
		holders.add(ec4);
		
		endCells = new ArrayList<IHolder>();
		endCells.add(ec1);
		endCells.add(ec2);
		endCells.add(ec3);
		endCells.add(ec4);
		
	}
	private void fillFreeCells() {
		Cell fc1 = new Cell(Game.Cell.FREE_CELL_ONE.ordinal()+11, gv, 
			new Point(GameView.CELL_X_OFFSET+0*(GameView.CARD_WIDTH+GameView.CELL_X_OFFSET),GameView.CELL_Y_OFFSET));
		Cell fc2 = new Cell(Game.Cell.FREE_CELL_TWO.ordinal()+11, gv, 
			new Point(GameView.CELL_X_OFFSET+1*(GameView.CARD_WIDTH+GameView.CELL_X_OFFSET),GameView.CELL_Y_OFFSET));
		Cell fc3 = new Cell(Game.Cell.FREE_CELL_THREE.ordinal()+11, gv, 
			new Point(GameView.CELL_X_OFFSET+2*(GameView.CARD_WIDTH+GameView.CELL_X_OFFSET),GameView.CELL_Y_OFFSET));
		Cell fc4 = new Cell(Game.Cell.FREE_CELL_FOUR.ordinal()+11, gv, 
			new Point(GameView.CELL_X_OFFSET+3*(GameView.CARD_WIDTH+GameView.CELL_X_OFFSET),GameView.CELL_Y_OFFSET));
		
		holders.add(fc1);
		holders.add(fc2);
		holders.add(fc3);
		holders.add(fc4);
	}
	private void fillColumns() {		
		piles = game.getPiles();
		columns = new Column[piles.length];
		for (int i=0; i<piles.length; i++) {
			columns[i] = new Column(i, gv);
			holders.add(columns[i]);	
			fillColumn(i);
		}
	}
	private void fillColumn(int idx) {
		ResourceLocator rl = ResourceLocator.getInstance();
		for (int j=0; j<piles[idx].toArray().length; j++) {				
			pro.view.core.Card newCard = new pro.view.core.Card(columns[idx]);
			pro.model.core.Card oldCard = (pro.model.core.Card) piles[idx].toArray()[j];
//			newCard.setText(oldCard.toString());
			ImageIcon icon = rl.getIcon(oldCard.toString());
			newCard.setIcon(icon);
			columns[idx].add(newCard);
		}
	}
	
	
	/**
	 * @return  the holders
	 * @uml.property  name="holders"
	 */
	public  List<IHolder> getHolders() {
		return holders;
	}
	
	/**
	 * @return  the endCells
	 * @uml.property  name="endCells"
	 */
	public  List<IHolder> getEndCells() {
		return endCells;
	}
	
	private void synchronize(IHolder dstHolder) {
		List<pro.view.core.Card> out = movedCards();
		System.out.println("movedCards : "+out.size());
		for (int i=0; i<out.size(); i++) {
			//System.out.println(out.get(i).toString());
			dstHolder.add(out.get(i));
		}
		srcHolder=null;
		System.out.println("out of sync");
	}
	
	private List<pro.view.core.Card> movedCards() {
		int src = srcHolder.getId();
		if (	(src>=0)	&&	(src<piles.length)	) {
			int diff = srcHolder.size() - piles[src].size();
			return srcHolder.removeCards(diff);
		}
		
		if (	(src>10)	&&	(src<=14)	) {
			int diff;
//			System.out.println("returning card");
			if (game.getFreeCells()[src-11]==null) {
				diff=1;
			} else { diff=0; }
			return srcHolder.removeCards(diff);
		}
		return null;
	}
	
	public boolean moveFrom(IHolder holder, int n) {
		int src = holder.getId() + 1;
		//System.out.println("in");
		if (	(src>0)	&&	(src<=piles.length)	) {
			try {
				game.moveFromPile(src, n);	
				System.out.println(game);
				srcHolder=holder;
				return true;
			} catch (Exception e) {System.out.println(e.getMessage()); return false;}

		}
		src--;
		if (	(src>10)	&&	(src<=14)	) {
			try {				
				src-=11;
//				System.out.println(src);
				game.moveFromFreeCell(Game.Cell.values()[src]);				
				System.out.println(game);
				srcHolder=holder;
				return true;
			} catch (Exception e) {System.out.println(e); return false;}
		}
		
			
		return false;
	}
	
	public boolean moveTo(IHolder holder) {
		int dst = holder.getId() + 1;
		if (	(dst>0)	&&	(dst<=piles.length)	) {
			try {				
				game.moveToPile(dst);
				synchronize(holder);
				System.out.println(game);
				signal(this);
//				System.out.println("holder: " +holder);				
//				System.out.println("find null");
				return true;
			} catch (Exception e) {System.out.println(e.getMessage()); return false;}

		}
		dst--;
		if (	(dst>10)	&&	(dst<=14)	) {
			try {				
				dst-=11;
				//System.out.println(dst);
				game.moveToFreeCell(Game.Cell.values()[dst]);	
				synchronize(holder); 	
				System.out.println(holder);
				signal(this);
				System.out.println(game);
				return true;
			} catch (Exception e) {
				System.out.println(e.getMessage()); 
				//System.out.println(game);
				//signal(holder);
				return false;
			}
		}
		
		
		if  (	(dst>20)	&&	(dst<=24)	) {
			try {
				dst-=21;
				int dstCmp = 0;
				switch (game.getCurrentCard().get(0).getSuit()) {
					case Spade : dstCmp = 0; break;
					case Diamond : dstCmp = 1; break; 
					case Heart : dstCmp = 2; break; 
					case Club : dstCmp = 3; break; 
				}
				if (dst==dstCmp) {					
					//if (game.getLastCardsOut().
					boolean result = game.moveToPlayedCards();
					synchronize(holder); 	
					//System.out.println(holder);
					signal(this);
					System.out.println(game);
					return result;
				}
				moveTo(srcHolder);
				System.out.println("Not the good emplacement: "+ dstCmp);
				System.out.println(game);
				return false;
			} catch (Exception e) {
				System.out.println(e.getMessage()); 
				//System.out.println(game);
				//signal(holder);
				return false;
			}
		}
		
		
		return false;
	}
	
	public void delete() {
		for (IHolder ih: holders) {
			ih.delete();
		}
	}
	
	private void signal(Object o) {	
//		gv.update(this, null);
		setChanged();
		notifyObservers(o);
	}
}
